package org.sunspotworld;

import com.sun.spot.util.IEEEAddress;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Observable;
import java.util.Observer;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SpringLayout;

/**
 *
 * @author Dustin
 * @version 1.0
 */
public class View extends JFrame implements Observer, Protocol, GameStates {

    private Model model;
    private JPanel scorePanel;
    private JTextField playTimeField;
    private JComboBox playTimeFormatBox;
    private JButton sendButton;
    private Controller controller;
    private JLabel currentplayTimeLabel;
    private JLabel playTimeLabel;
    private JPanel timePanel;

    public View(Model model, Host host) {
        super("Host Potato");
        this.model = model;
        model.addObserver(this);
        controller = new Controller(this, host, model);
        setUp();
    }

    /* Command to set up this View. All components will be created here.*/
    private void setUp() {
        scorePanel = new JPanel();
        scorePanel.setLayout(new FlowLayout(FlowLayout.LEADING));
        scorePanel.setBackground(Color.WHITE);


        currentplayTimeLabel = new JLabel();
        currentplayTimeLabel.setFont(new Font(currentplayTimeLabel.getFont().getFontName(),
                currentplayTimeLabel.getFont().getStyle(), 32));
        playTimeLabel = new JLabel("Speeltijd: ", JLabel.TRAILING);
        playTimeField = new IntegerTextField("0");
        playTimeField.setHorizontalAlignment(JTextField.TRAILING);
        playTimeFormatBox = new JComboBox();
        playTimeFormatBox.addActionListener(controller);
        playTimeFormatBox.addItem("Seconden");
        playTimeFormatBox.addItem("Minuten");
        playTimeFormatBox.addItem("Uren");
        sendButton = new JButton("Versturen");
        sendButton.setActionCommand("SEND");
        sendButton.addActionListener(controller);

        timePanel = new JPanel(new SpringLayout());
        timePanel.add(playTimeLabel);
        timePanel.add(playTimeField);
        timePanel.add(playTimeFormatBox);
        timePanel.add(sendButton);
        SpringUtilities.makeCompactGrid(timePanel, 1, 4, 6, 6, 6, 6);

        JPanel mainPanel = new JPanel(new BorderLayout());
        mainPanel.add(timePanel, BorderLayout.NORTH);
        mainPanel.add(scorePanel, BorderLayout.CENTER);

        getContentPane().add(mainPanel);

        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(900, 375);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    /**
     * Command to update this View by removing all components and add everything
     * by querying the Model.
     * @param o
     * @param arg
     */
    public void update(Observable o, Object arg) {
        scorePanel.removeAll();
        for (int i = 0; i < model.getSunSPOTs().size(); i++) {
            SunSPOT currentSpot = ((SunSPOT) model.getSunSPOTs().get(i));

            String address = IEEEAddress.toDottedHex(currentSpot.getAddress());
            address = address.substring(15);
            JLabel addressLabel = new JLabel(address);
            addressLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

            String path = "\\src\\org\\sunspotworld\\" +
                    "resources\\SunSPOT_white.jpg";
            ImageIcon icon =
                    new ImageIcon(this.getClass().getClassLoader().getResource(path));
            JLabel imageLabel = new JLabel(icon);
            imageLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

            JLabel scoreLabel = new JLabel(currentSpot.getScore() + "");
            scoreLabel.setAlignmentX(Component.CENTER_ALIGNMENT);

            JPanel statePanel = new JPanel();
            statePanel.setBackground(parseStateToColor(currentSpot.getState()));
            statePanel.add(new JLabel(parseStateToString(currentSpot.getState())));

            JPanel singleSPOT = new JPanel() {
            };
            singleSPOT.setLayout(new BoxLayout(singleSPOT, BoxLayout.Y_AXIS));
            singleSPOT.setBackground(Color.WHITE);
            singleSPOT.add(addressLabel);
            singleSPOT.add(imageLabel);
            singleSPOT.add(scoreLabel);
            singleSPOT.add(statePanel);

            scorePanel.add(singleSPOT);
        }

        if (timePanel.getComponentCount() == 1) {
            long time = model.getCurrentPlayTime();
            int seconds = (int) time % 60;
            time /= 60;
            int minutes = (int) time % 60;
            time /= 60;
            int hours = (int) time % 60;
            String hoursAsString = hours + "";
            String minutesAsString = minutes + "";
            String secondsAsString = seconds + "";
            if (hours < 10) {
                hoursAsString = "0" + hoursAsString;
            }
            if (minutes < 10) {
                minutesAsString = "0" + minutesAsString;
            }
            if (seconds < 10) {
                secondsAsString = "0" + secondsAsString;
            }
            currentplayTimeLabel.setText(hoursAsString + ":" + minutesAsString + ":" + secondsAsString);
        }

        scorePanel.revalidate();
        scorePanel.repaint();
    }

    private String parseStateToString(int aState) {
        String state = "";
        switch (aState) {
            case INITIAL:
                state = "Init";
                break;
            case WAIT:
                state = "Wachten";
                break;
            case HASPOTATOE:
                state = "Heeft Potatoe";
                break;
            case WAITINGFORPOTATOE:
                state = "Wacht op Potatoe";
                break;
            case CHOOSEPOTATOELIFETIME:
                state = "Tijd bepalen";
                break;
            case WINNER:
                state = "Winnaar";
                break;
            case LOSER:
                state = "Verloren";
                break;
        }
        return state;
    }

    private Color parseStateToColor(int aState) {
        Color state = Color.BLACK;
        switch (aState) {
            case INITIAL:
            case WAIT:
                state = Color.BLUE;
                break;
            case HASPOTATOE:
                state = Color.YELLOW;
                break;
            case WAITINGFORPOTATOE:
                state = Color.CYAN;
                break;
            case CHOOSEPOTATOELIFETIME:
                state = Color.ORANGE;
                break;
            case WINNER:
                state = Color.LIGHT_GRAY;
                break;
            case LOSER:
                state = Color.RED;
                break;
        }
        return state;
    }

    /**
     * Command to set the time panel. If the given value is true, the panel will
     * be set to allow input of playtime, of false the panel will be set to
     * display the play time.
     * @param value boolean If the time panel must be set for input or display
     */
    private void setTimePanel(boolean value) {
        timePanel.removeAll();
        if (value) {
            timePanel.setLayout(new SpringLayout());
            timePanel.add(playTimeLabel);
            timePanel.add(playTimeField);
            timePanel.add(playTimeFormatBox);
            timePanel.add(sendButton);
            SpringUtilities.makeCompactGrid(timePanel, 1, 4, 6, 6, 6, 6);
        } else {
            timePanel.setLayout(new FlowLayout());
            timePanel.add(currentplayTimeLabel);
        }
        timePanel.revalidate();
        timePanel.repaint();
    }

    /**
     * Private class that will handle all actionEvent that may come up.
     */
    private class Controller implements ActionListener {

        private Host host;
        private Model model;
        private View view;

        public Controller(View aView, Host aHost, Model aModel) {
            view = aView;
            host = aHost;
            model = aModel;
        }

        public void actionPerformed(ActionEvent ev) {
            if (ev.getActionCommand().equals("SEND")) {
                long playTime = Long.parseLong(playTimeField.getText());

                if (playTimeFormatBox.getSelectedIndex() > 0) {
                    playTime *= 60;
                }
                if (playTimeFormatBox.getSelectedIndex() == 2) {
                    playTime *= 60;
                }
                playTime *= 1000;

                if (playTime == 0) {
                    JOptionPane.showMessageDialog(view,
                            "Speeltijd is onjuist!", "Foutmelding...",
                            JOptionPane.ERROR_MESSAGE);
                } else {
                    model.setPlayTime(playTime, this);
                    host.broadcast(SET_GAMETIME + " " + playTime);
                    setTimePanel(false);
                }
            } else if (ev.getActionCommand().equals("TIMER")) {
                if (model.getCurrentPlayTime() > 0) {
                    model.updatePlayTime();
                } else {
                    model.setPlayTime(-1, this);
                    playTimeField.setText("0");
                    playTimeFormatBox.setSelectedIndex(0);
                    setTimePanel(true);
                }
            }
        }
    }

    /**
     * Private class that implements a JTextField and allows only numerics to
     * be entered.
     */
    private class IntegerTextField extends JTextField {

        final static String badchars = "`~!@#$%^&*()_+=\\|\"':;?/>.<, ";

        private IntegerTextField(String defaultText) {
            setText(defaultText);
        }

        public void processKeyEvent(KeyEvent ev) {

            char c = ev.getKeyChar();

            if ((Character.isLetter(c) && !ev.isAltDown()) || badchars.indexOf(c) > -1) {
                ev.consume();
                return;
            }
            if (c == '-' && getDocument().getLength() > 0) {
                ev.consume();
            } else {
                super.processKeyEvent(ev);
            }
        }
    }
}
